package com.treeroot.treenet.protocol.abs.udp;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;

/**
 * Create By TreeRoot
 * Create Time: 2023/12/18 03:42
 * Class Name: BaseUdpConnection
 * Description:
 * 基础Upd连接
 *
 * @author TreeRoot
 */
public abstract class AbsUdpConnection implements AbstractBaseUdpConnection {
    private static final Logger log = LoggerFactory.getLogger(AbsUdpConnection.class);

    @Override
    public void handleRequest(Consumer<BaseUdpVo> acceptConnectionConsumer) {
        BaseUdpVo baseUdpVo = new BaseUdpVo();
        try {
            Selector selector = Selector.open();
            baseUdpVo.setSelector(selector);
            DatagramChannel datagramChannel = DatagramChannel.open();
            datagramChannel.bind(new InetSocketAddress(9998));
            datagramChannel.configureBlocking(false);
            baseUdpVo.setDatagramChannel(datagramChannel);
            datagramChannel.register(selector, SelectionKey.OP_READ);
            while (true) {
                if (selector.select() == 0) {
                    continue;
                }
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey next = keyIterator.next();
                    if (next.isReadable()) {
                        acceptBefore(baseUdpVo);
                        acceptConnectionConsumer.accept(baseUdpVo);
                        acceptAfter(baseUdpVo);
                        keyIterator.remove();
                    }
                }
            }
        } catch (Exception e) {
            log.error("HandleUdpRequest.handleRequest", e);
        } finally {
            if (baseUdpVo.getDatagramChannel() != null) {
                try {
                    baseUdpVo.getDatagramChannel().close();
                } catch (Exception e) {
                    log.error("关闭通道资源失败", e);
                }
            }
            if (baseUdpVo.getSelector() != null) {
                try {
                    baseUdpVo.getSelector().close();
                } catch (Exception e) {
                    log.error("关闭选择器资源失败", e);
                }
            }
        }
    }

    public abstract void acceptBefore(BaseUdpVo baseUdpVo);

    public abstract void acceptAfter(BaseUdpVo baseUdpVo);
}
